package com.monitor.log.biz;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.monitor.log.biz.core.BizLogData;
import com.monitor.log.biz.core.BizLogUtil;
import com.ms.client.monitor.api.pojo.BizLog;
import com.ms.client.monitor.api.pojo.BizLogDtl;
import com.system.comm.utils.FrameHttpRequestUtil;
import com.system.comm.utils.FrameJsonUtil;
import com.system.comm.utils.FrameTimeUtil;

/**
 * aop记录日志
 * 	在配置文件中新增 save.log.open=1；代表打开记录日志
 * 	在配置文件中新增 save.log.exclude.url=/main/index；代表不进行日志记录的路径[多个,分隔]
 * @author yuejing
 * @date 2019年11月29日 下午4:28:54
 */
@Component
@Aspect
public class BizLogAspect {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(BizLogAspect.class);

	/**
	 * Controller层切点 注解拦截
	 */
	@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
	public void controllerAspect() {
	}
	/**
	 * 用于拦截Controller层记录用户的操作的开始时间
	 *
	 * @param joinPoint 切点
	 * @throws InterruptedException
	 */
	@Before("controllerAspect()")
	public void doBefore(JoinPoint joinPoint) throws InterruptedException {
		if (!BizLogUtil.isOpen()) {
			return;
		}
		Date beginTime = new Date();
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		String traceId = BizLogUtil.getTraceId();
		//线程绑定变量（该数据只有当前请求的线程可见）
		BizLogUtil.setBeginTime(beginTime);
		if (LOGGER.isDebugEnabled()) {
			//这里日志级别为debug
			LOGGER.debug("开始计时: {}  URI: {} traceId: {}", FrameTimeUtil.parseString(beginTime), request.getRequestURI(), traceId);
		}
		//读取session中的用户
		/*HttpSession session = request.getSession();
		User user = (User) session.getAttribute("user");
		System.out.println(user);*/
	}
	/**
	 * 用于拦截Controller层记录用户的操作
	 *
	 * @param joinPoint 切点
	 */
	@After("controllerAspect()")
	public void doAfter(JoinPoint joinPoint)throws Exception {
		if (!BizLogUtil.isOpen()) {
			return;
		}
		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
		//本机的IP
		String remoteAddr = BizLogUtil.getIp();
		//请求的Uri
		String requestUri = request.getRequestURI();
		BizLogUtil.setCurUri(requestUri);
		String requestUrl = request.getRequestURL().toString();
		BizLog bizLog = new BizLog();
		String traceId = BizLogUtil.getTraceId();
		bizLog.setTraceId(traceId);
		bizLog.setReqTime(FrameTimeUtil.getTime());
		bizLog.setReqParam1(BizLogUtil.getReqParam1());
		bizLog.setReqParam2(BizLogUtil.getReqParam2());
		bizLog.setReqParam3(BizLogUtil.getReqParam3());
		String spanId = BizLogUtil.getSpanId();
		List<BizLogDtl> dtls = new ArrayList<BizLogDtl>();
		Long reqTime = System.currentTimeMillis();
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_PATH, requestUri));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_URL, requestUrl));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_REMOTE_ADDR, remoteAddr));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_SERVICE_ID, BizLogUtil.getServiceId()));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_REQUEST_TIME, FrameTimeUtil.parseString(new Date(reqTime))));
		Map<String, Object> params = FrameHttpRequestUtil.getReqParams(request);
		if (params.size() == 0) {
			params = FrameHttpRequestUtil.getReqBodyParams(request);
		}
		String paramString = FrameJsonUtil.toString(params);
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_PARAMS, paramString));
		bizLog.setDtls(dtls);
		
		//通过线程池来执行日志保存
		BizLogUtil.saveLog(bizLog);
	}
	
	@AfterReturning(value = "controllerAspect()",returning="resultMap")
    public void controllerAspect(JoinPoint joinpoint, Object resultMap) throws Throwable {
		if (!BizLogUtil.isOpen()) {
			return;
		}
		//请求的Uri
		BizLog bizLog = new BizLog();
		String traceId = BizLogUtil.getTraceId();
		bizLog.setTraceId(traceId);
		bizLog.setReqTime(FrameTimeUtil.getTime());
		bizLog.setReqParam1(BizLogUtil.getReqParam1());
		bizLog.setReqParam2(BizLogUtil.getReqParam2());
		bizLog.setReqParam3(BizLogUtil.getReqParam3());
		String spanId = BizLogUtil.getSpanId();
		List<BizLogDtl> dtls = new ArrayList<BizLogDtl>();
		String response = null;
		if (resultMap != null) {
			response = FrameJsonUtil.toString(resultMap);
		}
		Long reqTime = System.currentTimeMillis();
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_RESPONSE, response));
		dtls.add(new BizLogDtl(spanId, traceId, reqTime,
				BizLogData.HTTP_RESPONSE_TIME, FrameTimeUtil.parseString(new Date(reqTime))));
		bizLog.setDtls(dtls);
		
		//通过线程池来执行日志保存
		BizLogUtil.saveLog(bizLog);
	}
	/**
	 *  异常通知 记录操作报错日志
	 * @param joinPoint
	 * @param e
	 */
	@AfterThrowing(pointcut = "controllerAspect()", throwing = "e")
	public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
		if (!BizLogUtil.isOpen()) {
			return;
		}
		String traceId = BizLogUtil.getTraceId();
		String spanId = BizLogUtil.getSpanId();
		BizLog bizLog = new BizLog();
		bizLog.setTraceId(traceId);
		bizLog.setReqTime(FrameTimeUtil.getTime());
		bizLog.setReqParam1(BizLogUtil.getReqParam1());
		bizLog.setReqParam2(BizLogUtil.getReqParam2());
		bizLog.setReqParam3(BizLogUtil.getReqParam3());
		List<BizLogDtl> dtls = new ArrayList<BizLogDtl>();
		BizLogDtl dtl = new BizLogDtl();
		dtl.setTraceId(traceId);
		dtl.setSpanId(spanId);
		dtl.setReqTime(System.currentTimeMillis());
		dtl.setReqKey("error");
		dtl.setReqValue("error info");
		dtls.add(dtl);
		bizLog.setDtls(dtls);
		
		BizLogUtil.saveLog(bizLog);
	}
	
}